// 源于Inferno utils/6l/l.h及相关文件。
// https:
// 
// 版权所有©1994-1999朗讯科技有限公司。保留所有权利。
// 版权所有©1995-1997 C H Forsyth(forsyth@terzarima.net)
// 部分版权©1997-1999维塔诺瓦有限公司
// 部分版权©2000-2007维塔诺瓦控股有限公司（www.vitanuova.com）
// 部分版权©20042006布鲁斯·埃利斯
// 修订版权©2000-2007朗讯科技有限公司及其他
// 部分版权©2009 Go作者。保留所有权利。
// 
// 特此免费授予获得本软件及相关文档文件（以下简称“软件”）副本
// 的任何人在本软件中不受限制地处理
// 的权利，包括但不限于
// 使用、复制、修改、合并、发布、分发、再许可的权利，和/或出售本软件的
// 副本，并允许提供本软件的人员在以下条件下这样做：
// 
// 上述版权声明和本许可声明应包含在
// 本软件的所有副本或大部分中。
// 
// 本软件按“原样”提供，不提供任何形式的明示或暗示担保，包括但不限于适销性担保、
// 适用于特定用途和非侵权性担保。在任何情况下，
// 作者或版权持有人均不对任何索赔、损害赔偿或其他
// 责任承担责任，无论是合同诉讼、侵权诉讼还是其他诉讼，均由
// 因本软件或本软件的使用或其他交易引起，或与本软件或本软件的使用或其他交易有关。

package objabi

type RelocType int16

// go:generate stringer-type=RelocType 
const (
	R_ADDR RelocType = 1 + iota
	// R_ADDRPOWER重新定位一对“D-form”指令（指令字的下半部分包含16位
	// 立即），后面通常是
	// ，将引用符号的地址的“高调整”16位插入第一条指令的立即数字段，将低16位插入第二条指令的立即数字段。
	R_ADDRPOWER
	// R_ADDRARM64重新定位adrp，添加对以计算
	// 引用符号的地址。
	R_ADDRARM64
	// R_ADDRMIPS（仅用于mips/mips64）通过将外部
	// 地址编码到指令中，将其解析为低16位。
	R_ADDRMIPS
	// R_ADDROFF解析为一个32位的偏移量，该偏移量是从节
	// 的开头开始的，用于保存重新定位到引用符号的数据。
	R_ADDROFF
	R_SIZE
	R_CALL
	R_CALLARM
	R_CALLARM64
	R_CALLIND
	R_CALLPOWER
	// R_CALLMIPS（仅用于mips64）通过将地址编码到指令中，解析为CALL（JAL）指令的非PC相对目标地址
	// 。
	R_CALLMIPS
	R_CONST
	R_PCREL
	// R_TLS_LE，用于386、amd64和ARM，解析为
	// 线程本地符号与线程本地基的偏移量，并用于实现用于TLS访问的
	// “local exec”模型（R.Sym不是在英特尔平台上设置的，而是
	// 外部链接时在链接器中设置为TLS符号--runtime.tlsg）。
	R_TLS_LE
	// R_TLS_IE，使用386，amd64，ARM解析到PC相对偏移量到一个GET 
	// 插槽，该插槽包含从线程本地符号到线程本地
	// 基的偏移量，并用于实现tls访问的“初始执行”模型（r.Sym 
	// 未在英特尔平台上设置，但在外部链接时，在
	// 链接器中设置为TLS符号runtime.tlsg）。
	R_TLS_IE
	R_GOTOFF
	R_PLT0
	R_PLT1
	R_PLT2
	R_USEFIELD
	// R_USETYPE解析为*rtype，但不创建重定位。
	// 链接器将其用作一个信号，指示指向的类型信息
	// 应链接到最终二进制文件中，即使没有其他
	// 直接引用。（这用于可通过反射访问的类型。）
	R_USETYPE
	// R_USEIFACE标记一个类型被转换为应用此
	// 重新定位的函数中的接口。目标是一个类型描述符。这是一个标记重新定位（0大小），用于链接器的可达性分析。
	R_USEIFACE
	// R_USEIFACEMETHOD标记函数
	// 应用此重新定位的接口方法。目标是一个接口类型描述符。
	// 加数是类型描述符中方法的偏移量。这是一个标记重新定位（0大小），用于链接器的可达性分析。
	R_USEIFACEMETHOD
	// 与R_USEIFACEMETHOD类似，除了用Sym+Add代替type+
	// 方法偏移外，Sym指向一个包含被调用方法的名称
	// 的符号。参见
	// cmd/compile/internal/reflectdata/reflect中的描述。go:MarkUsedIfaceMethod了解详细信息。
	R_USEGENERICIFACEMETHOD
	// R_METHODOFF解析为从节开始的32位偏移量
	// 保存要重新定位到引用符号的数据。
	// 它是从
	// /*rtype的UncoMonType链接时使用的R_ADDROFF的变体，如果链接器确定链接程序无法访问
	// /*文本的方法，则可以将其设置为零。
	R_METHODOFF
	// R_KEEP告诉链接器在最终二进制文件中保留引用的符号
	// 如果包含R_KEEP重定位的符号在最终二进制文件中。
	R_KEEP
	R_POWER_TOC
	R_GOTPCREL
	// R_JMPMIPS（仅用于mips64）通过将地址编码到指令中，解析为JMP指令的非PC相对目标地址
	// 。
	// 堆栈nosplit检查忽略此项，因为它不是函数调用。
	R_JMPMIPS

	// R_DWARFSECREF解析为符号与其部分的偏移量。
	// 搬迁目标必须为4号（在当前实施中）。
	R_DWARFSECREF

	// R_DWARFFILEREF解析为侏儒的索引。调试行
	// 指定文件符号的文件表。必须应用于窗体DW_form_data4的
	// 属性。
	R_DWARFFILEREF

	// 依赖于平台的重新定位。具有固定宽度指令
	// 的体系结构固有的问题是32位（或64位！）位移不能被写入一条32位指令中，因此一个地址需要在多条指令中分布，而这又需要一系列的重新定位，每个指令更新一部分。这会导致重新定位代码
	// 固有的特定于处理器。

	// Arm64。

	// 将MOV[NZ]立即数字段设置为从线程
	// 局部基到被引用（线程
	// 局部）符号定义的线程局部变量的偏移量的位[15:0]。如果偏移量不适合16位，则出错。
	R_ARM64_TLS_LE

	// 重新安置ADRP；LD64指令序列，用于加载
	// 线程本地基和由GOT中的
	// 引用（线程本地）符号定义的线程本地变量之间的偏移量。
	R_ARM64_TLS_IE

	// R_ARM64_GOTPCREL重新定位adrp、ld64对，以计算所引用符号的已获取
	// 插槽的地址。
	R_ARM64_GOTPCREL

	// R_ARM64_GOT解析一个GET相对指令序列，通常是一个adrp 
	// 后跟另一条ld指令。
	R_ARM64_GOT

	// R_ARM64_PCREL解析PC相对地址指令序列，通常是一个
	// adrp，后跟另一条add指令。
	R_ARM64_PCREL

	// R_ARM64_LDST8将LD/ST立即数设置为本地地址的位[11:0]。
	R_ARM64_LDST8

	// R_ARM64_LDST16将LD/ST立即数设置为本地地址的位[11:1]。
	R_ARM64_LDST16

	// R_ARM64_LDST32将LD/ST立即数设置为本地地址的位[11:2]。
	R_ARM64_LDST32

	// R_ARM64_LDST64将LD/ST立即数设置为本地地址的位[11:3]。
	R_ARM64_LDST64

	// R_ARM64_LDST128将LD/ST立即数设置为本地地址的位[11:4]。
	R_ARM64_LDST128

	// PPC64。

	// R\u POWER\u TLS\LE用于实现TLS的“本地执行”模型
	// access。它解析为线程本地符号与
	// 线程指针（R13）的偏移量，并根据
	// 支持32位位移的一对指令进行拆分。
	R_POWER_TLS_LE

	// R_POWER_TLS_IE用于实现TLS访问的“初始执行”模型。它
	// 重新定位D格式、DS格式的指令序列，如R_ADDRPOWER_DS。它
	// 为TOC中的线程本地符号插入GOT插槽的偏移量（动态链接器用线程本地
	// GOT插槽）。
	// 符号与线程指针（R13）的偏移量填充
	R_POWER_TLS_IE

	// R_POWER_TLS将一条X形式指令（如“ADD R3，R13，R4”）标记为完成
	// GOT相对重定位序列以计算TLS地址。这可以是
	// 系统链接器用来将GOT相对TLS重新定位重写为
	// 更简单的线程指针相对重新定位。关于此转换，请参见
	// ppc64 elfv2 1.4 ABI中的表3.26和3.28。同样，第二个参数
	// （在X形式指令中通常称为RB）被假定为R13。
	R_POWER_TLS

	// R_ADDRPOWER_DS与上面的R_ADDRPOWER类似，但假设第二条
	// 指令是一条“DS格式”指令，它有一个立即数字段，占据指令字的
	// 位[15:2]。
	// 重新定位符号的地址的位[15:2]插入该字段；如果地址的最后两个
	// 位不是0，则为错误。
	R_ADDRPOWER_DS

	// R_ADDRPOWER_PCREL重新定位D-form、DS-form指令序列，如
	// R_ADDRPOWER_DS，但插入引用符号
	// 的GOT插槽从TOC而非符号地址的偏移量。
	R_ADDRPOWER_GOT

	// R_ADDRPOWER_PCREL重新定位两条D格式指令，如R_ADDRPOWER，但
	// 插入从重新定位位置到
	// 重新定位符号地址的位移，而不仅仅是其地址。
	R_ADDRPOWER_PCREL

	// R_ADDRPOWER_TOCREL重新定位两条D格式指令，如R_ADDRPOWER，但
	// 插入从TOC到重新定位符号地址的偏移量
	// 而不是符号地址。
	R_ADDRPOWER_TOCREL

	// R_ADDRPOWER_TOCREL重新定位D格式、DS格式的指令序列，如
	// R_ADDRPOWER_DS，但插入从TOC到
	// 重新定位符号地址的偏移量，而不是符号的地址。
	R_ADDRPOWER_TOCREL_DS

	// RISC-V.

	// R_RISCV_调用使用21位PC相对
	// 地址重新定位J-type指令。
	R_RISCV_CALL

	// R_RISCV_CALL_TRAMP与R_RISCV_CALL相同，但表示使用
	// trampoline，我们可以在搬迁期间避免使用。这些是
	// 仅由链接器使用，而不是由编译器或汇编程序发出。
	R_RISCV_CALL_TRAMP

	// R_RISCV_PCREL_ITYPE使用
	// AUIPC+I-type指令对解析32位PC相对地址。
	R_RISCV_PCREL_ITYPE

	// R_RISCV_PCREL_STYPE使用
	// AUIPC+S型指令对解析32位PC相对地址。
	R_RISCV_PCREL_STYPE

	// R_RISCV_TLS_IE_ITYPE使用AUIPC+I-type指令对解析32位TLS初始执行TOC偏移量
	// 地址。
	R_RISCV_TLS_IE_ITYPE

	// R_RISCV_TLS_IE_STYPE使用AUIPC+S型指令对解析32位TLS初始执行TOC偏移量
	// 地址。
	R_RISCV_TLS_IE_STYPE

	// R_PCRELDBL重新定位s390x 2字节对齐的PC相对地址。
	// TODO（mundaym）：一旦变体可以序列化，就删除它-参见14218期。
	R_PCRELDBL

	// R_ADDRMIPSU（仅用于mips/mips64）通过将外部地址编码到指令中，解析为外部地址的符号调整“上限”16 
	// 位（位16-31）。
	R_ADDRMIPSU
	// R_ADDRMIPSTLS（仅用于mips64）通过将TLS 
	// 地址（从线程指针的偏移量）编码到指令中，解析为TLS地址的低16位。
	R_ADDRMIPSTLS

	// R_addrchoff解析为从
	// 符号的DWARF编译单元开始的指针大小的偏移量。
	R_ADDRCUOFF

	// R_WASMIMPORT解析为WebAssembly函数导入的索引。
	R_WASMIMPORT

	// R_XCOFFREF（仅在aix/ppc64上使用）防止通过ld 
	// 对符号进行垃圾收集。这不是一个真正的重新定位，它可以放在任何地方
	// 在一个符号和目标的任何符号。
	R_XCOFFREF

	// R_WEAK将重新定位标记为弱引用。
	// 弱重定位不会使它所指的符号可访问，
	// 并且只有当符号以其他方式可访问时，链接器才会尊重
	// 重定位。
	R_WEAK = -1 << 15

	R_WEAKADDR    = R_WEAK | R_ADDR
	R_WEAKADDROFF = R_WEAK | R_ADDROFF
)

// IsDirectCall报告r是否是直接呼叫的重新定位。
// 直接调用是以目标地址
// 为立即数的调用指令。地址嵌入到指令中，可能是宽度有限的
// 地址。间接调用是一种调用指令，它采用
// 寄存器或内存中的目标地址。
func (r RelocType) IsDirectCall() bool {
	switch r {
	case R_CALL, R_CALLARM, R_CALLARM64, R_CALLMIPS, R_CALLPOWER, R_RISCV_CALL, R_RISCV_CALL_TRAMP:
		return true
	}
	return false
}

// IsDirectJump报告r是否为直接跳转的重新定位。
// 直接跳转是以目标地址
// 为立即数的JMP指令。该地址嵌入到指令中，可能是宽度有限的
// 地址。间接跳转是一条JMP指令，它接受
// 寄存器或内存中的目标地址。
func (r RelocType) IsDirectJump() bool {
	switch r {
	case R_JMPMIPS:
		return true
	}
	return false
}

// IsDirectCallOrJump报告r是否是直接
// 呼叫或直接跳转。
func (r RelocType) IsDirectCallOrJump() bool {
	return r.IsDirectCall() || r.IsDirectJump()
}
